﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Collections.Concurrent;

namespace yule.Common.WCF
{
    /// <summary>
    /// 服务容器
    /// </summary>
    public sealed class ServiceContext
    {

        /// <summary>
        /// 构造函数
        /// </summary>
        internal ServiceContext()
        {
            this.Initialize();
        }
        
        /// <summary>
        /// 初始化
        /// </summary>
        public void Initialize()
        {
            if (this.endpoints.Count > 0)
            {
                this.endpoints.Clear();
            }

            string ServiceURL = yule.Util.AppSettings.GetAppSetting(yule.Const.AppSettings.ServiceURL);

            System.Xml.XmlDocument document = null;

            if (yule.Util.Verificate.IsNull(ServiceURL) == false)
            {
                //远程读取
                string serviceXml = null;
                document = new System.Xml.XmlDocument();
                document.LoadXml(serviceXml);
            }
            else
            {
                //本地读取
                //ServiceSettings.xml
                string xmlPath = System.AppDomain.CurrentDomain.BaseDirectory + "ServiceSettings.xml";
                if (System.IO.File.Exists(xmlPath) == true)
                {
                    document = new System.Xml.XmlDocument();
                    document.Load(xmlPath);
                }
            }

            if (document != null)
            {
                System.Xml.XmlNode rootNode = document.SelectSingleNode("Services");


                foreach (System.Xml.XmlNode node in rootNode.ChildNodes)
                {
                    if (node.Name == "Service")
                    {
                        string t = node.Attributes["Type"].Value;
                        string e = node.Attributes["EndPoint"].Value;
                        Type type = Type.GetType(t);
                        this.endpoints.Add(type, e);
                    }
                }
            }

        }

        /*
        <binding sendTimeout="00:10:00" textEncoding="utf-8" allowCookies="true" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
          <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxNameTableCharCount="2147483647" />
          <security mode="None"/>
        </binding>
        */

        private IDictionary<Type, string> endpoints = new Dictionary<Type, string>();

        /// <summary>
        /// 地址:工厂缓存
        /// 线程安全
        /// </summary>
        private ConcurrentDictionary<string, ChannelFactory> cf = new ConcurrentDictionary<string, ChannelFactory>();

        /// <summary>
        /// 获取对应WCF工厂
        /// </summary>
        /// <typeparam name="T">契约类型</typeparam>
        /// <param name="endpointName">地址</param>
        /// <returns></returns>
        internal ChannelFactory<T> GetFactory<T>(string endpointName) where T : class
        {
            return cf.GetOrAdd
                (
                    endpointName,
                    (p_endpointName) =>
                    {

                        /*
                        ChannelFactoryCreator._Bind = new WSHttpBinding(SecurityMode.None);
                        ChannelFactoryCreator._Bind.SendTimeout = new TimeSpan(0, 10, 0);
                        ChannelFactoryCreator._Bind.MaxBufferPoolSize = 65536001L;
                        ChannelFactoryCreator._Bind.MaxReceivedMessageSize = 655360002L;
                        ChannelFactoryCreator._Bind.TextEncoding = Encoding.UTF8;
                        ChannelFactoryCreator._Bind.ReaderQuotas.MaxStringContentLength = 65536003;
                        ChannelFactoryCreator._Bind.ReaderQuotas.MaxArrayLength = 655360004;
                        ChannelFactoryCreator._Bind.ReaderQuotas.MaxBytesPerRead = 65536005;
                        */

                        System.ServiceModel.EndpointAddress address = new System.ServiceModel.EndpointAddress(p_endpointName);
                        //目前这里只支持 WSHttpBinding
                        //普通
                        //System.ServiceModel.WebHttpBinding
                        WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);
                        binding.SendTimeout = new TimeSpan(0, 10, 0);
                        binding.TextEncoding = System.Text.Encoding.UTF8;
                        binding.MaxBufferPoolSize = 65536001L;
                        binding.MaxReceivedMessageSize = 655360002L;
                        binding.ReaderQuotas.MaxStringContentLength = 65536003;
                        binding.ReaderQuotas.MaxArrayLength = 655360004;
                        binding.ReaderQuotas.MaxBytesPerRead = 65536005;
                        binding.AllowCookies = true;
                        ChannelFactory<T> factory = new ChannelFactory<T>(binding, address);

                        foreach (System.ServiceModel.Description.OperationDescription op in factory.Endpoint.Contract.Operations)
                        {
                            System.ServiceModel.Description.DataContractSerializerOperationBehavior dataContractBehavior =
                                        op.Behaviors.Find<System.ServiceModel.Description.DataContractSerializerOperationBehavior>()
                                        as System.ServiceModel.Description.DataContractSerializerOperationBehavior;

                            if (dataContractBehavior != null)
                            {
                                dataContractBehavior.MaxItemsInObjectGraph = int.MaxValue;
                            }

                        }


                        return factory;
                    }
                ) as ChannelFactory<T>;
        }


        /// <summary>
        /// 创建服务
        /// </summary>
        /// <typeparam name="T">契约类型</typeparam>
        /// <returns></returns>
        public T CreateService<T>() where T : class
        {

            Type type = typeof(T);
            string endpointName = null;
            this.endpoints.TryGetValue(type, out endpointName);

            if (endpointName == null)
            {
                throw new Exception(string.Format("{0}:对应的配置未找到。请检查服务配置", type.FullName));
            }

            return new WCF.ServiceRealProxy<T>(endpointName).GetTransparentProxy() as T;
        }

    }
}